/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						       creature_ability_properties.cpp

	$Header: /game/creature_ability_properties.cpp $

	$NoKeywords: $

 ************************************************************************/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "creature_ability_properties.h"

#include <vector>
#include "creature_ability.h"
#include "bitmap_group_cache.h"
#include "bitmap_layer_cache.h"
#include "elements_of.h"
#include "enum_map.h"
#include "enum_operations.h"
#include "string_pair.h"
#include "table.h"
#include "table_ptr.h"


// nasty little trick to declare a constant followed by a string with the constant's name.
#define DECLARE_KEYWORD( keyword ) k_ability_##keyword, #keyword

namespace
{
	static t_char_ptr_pair k_keywords[] = 
	{
		{ DECLARE_KEYWORD( 3_headed_attack ) },
		{ DECLARE_KEYWORD( aging ) },
		{ DECLARE_KEYWORD( area_effect ) },
		{ DECLARE_KEYWORD( berserk ) },
		{ DECLARE_KEYWORD( binding ) },
		{ DECLARE_KEYWORD( blind ) },
		{ DECLARE_KEYWORD( blinding ) },
		{ DECLARE_KEYWORD( block ) },
		{ DECLARE_KEYWORD( bloodlust ) },
		{ DECLARE_KEYWORD( breath_attack ) },
		{ DECLARE_KEYWORD( chaos_protection ) },
		{ DECLARE_KEYWORD( charging ) },
		{ DECLARE_KEYWORD( cold_attack ) },
		{ DECLARE_KEYWORD( cold_resistance ) },
		{ DECLARE_KEYWORD( curse ) },
		{ DECLARE_KEYWORD( death_protection ) },
		{ DECLARE_KEYWORD( devouring ) },
		{ DECLARE_KEYWORD( elemental ) },
		{ DECLARE_KEYWORD( extra_melee_attack ) },
		{ DECLARE_KEYWORD( extra_ranged_attack ) },
		{ DECLARE_KEYWORD( fire_attack ) },
		{ DECLARE_KEYWORD( fire_resistance ) },
		{ DECLARE_KEYWORD( fire_shield ) },
		{ DECLARE_KEYWORD( first_strike ) },
		{ DECLARE_KEYWORD( first_strike_immunity ) },
		{ DECLARE_KEYWORD( flying ) },
		{ DECLARE_KEYWORD( fortune ) },
		{ DECLARE_KEYWORD( freeze ) },
		{ DECLARE_KEYWORD( taxpayer ) },
		{ DECLARE_KEYWORD( giantslayer ) },
		{ DECLARE_KEYWORD( ignore_wards ) },
		{ DECLARE_KEYWORD( ignore_zones_of_control ) },
		{ DECLARE_KEYWORD( insubstantial ) },
		{ DECLARE_KEYWORD( hydra_strike ) },
		{ DECLARE_KEYWORD( hypnotize ) },
		{ DECLARE_KEYWORD( magic_immunity ) },
		{ DECLARE_KEYWORD( melee_giantslayer ) },
		{ DECLARE_KEYWORD( life_protection ) },
		{ DECLARE_KEYWORD( lightning ) },
		{ DECLARE_KEYWORD( long_range ) },
		{ DECLARE_KEYWORD( long_weapon ) },
		{ DECLARE_KEYWORD( magic_mirror ) },
		{ DECLARE_KEYWORD( magic_resistance ) },
		{ DECLARE_KEYWORD( mana_leech ) },
		{ DECLARE_KEYWORD( mechanical ) },
		{ DECLARE_KEYWORD( mirth ) },
		{ DECLARE_KEYWORD( negate_mind_immunity ) },
		{ DECLARE_KEYWORD( no_retaliation ) },
		{ DECLARE_KEYWORD( normal_melee ) },
		{ DECLARE_KEYWORD( panic ) },
		{ DECLARE_KEYWORD( poison ) },
		{ DECLARE_KEYWORD( random_curse ) },
		{ DECLARE_KEYWORD( ranged ) },
		{ DECLARE_KEYWORD( ranged_first_strike ) },
		{ DECLARE_KEYWORD( ranged_giantslayer ) },
		{ DECLARE_KEYWORD( ranged_stun ) },
		{ DECLARE_KEYWORD( rebirth ) },
		{ DECLARE_KEYWORD( regeneration ) },
		{ DECLARE_KEYWORD( resurrection ) },
		{ DECLARE_KEYWORD( sea_bonus ) },
		{ DECLARE_KEYWORD( shoots_twice ) },
		{ DECLARE_KEYWORD( short_range ) },
		{ DECLARE_KEYWORD( siege_machine ) },
		{ DECLARE_KEYWORD( skeletal ) },
		{ DECLARE_KEYWORD( spell_vulnerability ) },
		{ DECLARE_KEYWORD( spellcaster ) },
		{ DECLARE_KEYWORD( stealth ) },
		{ DECLARE_KEYWORD( stone_skin ) },
		{ DECLARE_KEYWORD( stone_gaze ) },
		{ DECLARE_KEYWORD( strength ) },
		{ DECLARE_KEYWORD( strike_and_return ) },
		{ DECLARE_KEYWORD( strikes_twice ) },
		{ DECLARE_KEYWORD( stunning ) },
		{ DECLARE_KEYWORD( summons_demons ) },
		{ DECLARE_KEYWORD( teleport ) },
		{ DECLARE_KEYWORD( terror ) },
		{ DECLARE_KEYWORD( toughness ) },
		{ DECLARE_KEYWORD( undead ) },
		{ DECLARE_KEYWORD( unlimited_retaliation ) },
		{ DECLARE_KEYWORD( unlimited_shots ) },
		{ DECLARE_KEYWORD( vampire ) },
		{ DECLARE_KEYWORD( weakness ) },
	};

	static t_enum_map<t_creature_ability> const k_map( k_keywords, 
		                                               ELEMENTS_OF( k_keywords ),
													   k_ability_count );

	struct t_ability_property
	{
		std::string name;
		std::string help;
	};

	static t_bitmap_group_cache const k_icons( "icons.skills.creature.52" );

	// table of properties, initialized from an excel spreadsheet.
	class t_property_table
	{
	public:
		t_property_table();

		t_ability_property const& operator[]( t_creature_ability ability ) const;
	protected:
		t_ability_property m_properties[k_ability_count];
	};

	inline t_ability_property const& t_property_table::operator []( t_creature_ability ability ) const
	{
		return m_properties[ability];
	}
};


// --------------------------------------------------------------
// constructor for property table
// --------------------------------------------------------------
enum 
{
	k_column_keyword,
	k_column_name,
	k_column_help_text
};

t_property_table::t_property_table()
{
	// read table
	t_table_cache const k_skill_table( "creature_abilities" );
	t_table_ptr			table = k_skill_table.get();
	t_table::iterator	line = table->begin();
	t_creature_ability  ability;

	line++;
	for (line = table->begin(); line != table->end(); line++)
	{
		if ((*line)[0].empty())
			continue;
		
		ability = k_map[(*line)[k_column_keyword]];
		if (ability < 0)
			continue;

		t_ability_property& properties = m_properties[ability];

		properties.name =	(*line)[k_column_name];
		properties.help =	(*line)[k_column_help_text];
	}
}

// --------------------------------------------------------------
// get property table
// --------------------------------------------------------------
static t_ability_property const& get_properties( t_creature_ability ability )
{
	static t_property_table table;

	return table[ability];
}

// --------------------------------------------------------------
// get keyword of a creature ability
// --------------------------------------------------------------
std::string	get_ability_keyword( t_creature_ability ability )
{
	return k_map[ability];
}

// --------------------------------------------------------------
// get name (for hover) of a creature ability
// --------------------------------------------------------------
std::string get_ability_name( t_creature_ability ability )
{
	return get_properties( ability ).name;
}

// --------------------------------------------------------------
// get right click text of a creature ability
// --------------------------------------------------------------
std::string	get_ability_help( t_creature_ability ability )
{
	return get_properties( ability ).help;
}

// --------------------------------------------------------------
// get icon of a creature ability
// --------------------------------------------------------------
t_bitmap_group_ptr	get_ability_icons( int height )
{
	return k_icons.get();
}
